package pt.inescid.components.messages;

import java.io.IOException;

import pt.inescid.components.commons.Resources;
import rice.p2p.commonapi.Endpoint;
import rice.p2p.commonapi.Id;
import rice.p2p.commonapi.Message;
import rice.p2p.commonapi.NodeHandle;
import rice.p2p.commonapi.NodeHandleSet;
import rice.p2p.commonapi.rawserialization.InputBuffer;
import rice.p2p.commonapi.rawserialization.OutputBuffer;
import rice.p2p.commonapi.rawserialization.RawMessage;
import rice.pastry.NodeSet;

/**
 * 
 * Task
 * 
 * @author Filipe Paredes
 * @author Sergio Esteves (sesteves at gsd.inesc-id.pt)
 */
public class Task implements RawMessage {

	public static final short TYPE = 1;

	private NodeHandleSet source;
	
	private int jobHandler;
	
	private int taskNumber;
	
	// cost for this task: cpu, memory, bandwidth & disk space	
	private double cpu,  mem,  bw;
	private long storage;

	// Application identifier
	private String appID;
	
	// ratio (inwork/outwork) of the sending node
	private double ratio;
	
	// Task's data
	private byte[] data;

	// application configuration
	private byte[] config;
	
	// Key used to search for this task result in Past
	private Id lookupKey;

	private static final long serialVersionUID = 7526472295622776147L;

	/**
	 * Task constructor
	 * 
	 * @param cpu - cpu cost
	 * @param mem - mem cost
	 * @param bw - bandwidth cost
	 * @param storage - storage cost
	 * @param config configuration file
	 * @param data data file
	 */
	public Task(NodeHandle source, int jobHandler, int taskNumber, 
			double cpu, double mem, double bw, long storage, 
			String appID, byte[] config, byte[] data, Id lookupKey) {
		this.source = new NodeSet();
		this.source.putHandle(source);
		this.jobHandler = jobHandler;
		this.taskNumber = taskNumber;
		this.cpu = cpu;
		this.mem = mem;
		this.bw = bw;
		this.storage = storage;
		this.appID = appID;
		this.config = config;
		this.data = data;
		this.lookupKey = lookupKey;
	}

	public Task(NodeHandle source, int jobHandler, int taskNumber, 
			Resources res, String appID, byte[] config, byte[] data, Id lookupKey) {
		this(source, jobHandler, taskNumber, res.getCPU(), res.getMem(), res.getBW(),
				res.getStorage(), appID, config, data, lookupKey);
	}
	
	public Id getSource(){
		return source.getHandle(0).getId();
	}
	
	public NodeHandleSet getSourceNHSet() {
		return source;
	}
	
	public int getJobHandler() {
		return jobHandler;
	}
	public int getTaskNumber() {
		return taskNumber;
	}
	public double getCPU() {
		return cpu;
	}
	public double getMem() {
		return mem;
	}
	public double getBW() {
		return bw;
	}
	public String getAppID() {
		return appID;
	}
	public double getRatio() {
		return ratio;
	}
	public byte[] getConfig() {
		return config;
	}
	public byte[] getData() {
		return data;
	}

	public Resources getCost() {
		return new Resources(cpu, mem, bw, storage);
	}

	public Id getLookupKey() {
		return lookupKey;
	}

	public void setRatio(double ratio) {
		this.ratio = ratio;
	}
	
	public String toString() {
		//return "Gridlet Cost: CPU="+cpu+" MEM="+mem;
		return "Task " + this.hashCode();
	}

	/**
	 * Use low priority to prevent interference with overlay maintenance traffic.
	 */
	public int getPriority() {
		return Message.LOW_PRIORITY;
	}

	public short getType() {
		return TYPE;
	}

	/**
	 * Deserializing constructor.  This does the "real" deserialization.
	 * 
	 * @param buf
	 * @param endpoint
	 * @throws IOException
	 */
	public Task(InputBuffer buf, Endpoint endpoint) throws IOException {
		source = endpoint.readNodeHandleSet(buf, buf.readShort());
		jobHandler = buf.readInt();
		taskNumber = buf.readInt();
		cpu = buf.readDouble();
		mem = buf.readDouble();
		bw = buf.readDouble();
		storage = buf.readLong();
		appID = buf.readUTF();
		ratio = buf.readDouble();
		config = new byte[buf.readInt()];
		buf.read(config);
		int len = buf.readInt();
		if(len != 0) {
			data = new byte[len];
			buf.read(data);
		}
		lookupKey = endpoint.readId(buf, buf.readShort());
	}

	public void serialize(OutputBuffer buf) throws IOException {
		buf.writeShort(source.getType());
		source.serialize(buf);
		buf.writeInt(jobHandler);
		buf.writeInt(taskNumber);
		buf.writeDouble(cpu);
		buf.writeDouble(mem);
		buf.writeDouble(bw);
		buf.writeLong(storage);
		buf.writeUTF(appID);
		buf.writeDouble(ratio);
		buf.writeInt(config.length);
		buf.write(config, 0, config.length);
		if(data == null)
			buf.writeInt(0);
		else {
			buf.writeInt(data.length);
			buf.write(data, 0, data.length);
		}
		buf.writeShort(lookupKey.getType());
		lookupKey.serialize(buf);
	}
}
